以YOLOv4模型框選中文字後,將資料集(約7萬張)區分為以下類別:
1.1 word(僅有1個中文字)
1.2 words(2個以上中文字)
1.3 no_word(無文字)
因「正式比賽時,每張圖檔內只會有一個最正確的中文字」,篩選出僅有1個中文字的圖檔作為新資料集。
篩選出word(僅有1個中文字)的圖檔後,仍有以下問題。
3.1 僅有1個中文字的圖檔,物件偵測框外仍有大面積空白。故以opencv-python去除空白背景。
3.2 裁切後的圖檔中,有許多錯誤的標籤(如,圖檔中的文字是「鴻」,標籤卻是「卓」)
3.3 更正標籤後的圖檔中,有部分標籤名稱不在主辦單位提供的800字內。
圖檔分類
1.1 物件偵測:讀取YOLOv4模型框選中文字,並回傳物件偵測框選範圍(boxes),取len(boxes)可以得知,該圖檔框選出幾個中文字。
import cv2
import numpy as np
import os
import shutil
#讀取模型與訓練權重
def initNet():
CONFIG = 'yolov4-tiny-myobj.cfg'
WEIGHT = 'yolov4-tiny-myobj_last.weights'
net = cv2.dnn.readNet(CONFIG,WEIGHT)
model = cv2.dnn_DetectionModel(net)
model.setInputParams(size=(416,416),scale=1/255.0)
model.setInputSwapRB(True)
return model
#物件偵測
def nnProcess(image, model):
classes, confs, boxes = model.detect(image, 0.4, 0.1)
return classes, confs, boxes
1.2 圖檔分類
#依照偵測到的物件數量進行分類
def copyClassify(file ,input, boxes, file_name, l, m, n):
box_num = len(boxes)
if box_num == 0:
shutil.copy2(input, './02_yolo_classify3/03_no_word/{}'.format(file_name))
print('※{}成功複製到no_word'.format(file))
elif box_num == 1:
shutil.copy2(input, './02_yolo_classify3/01_word/{}'.format(file_name))
print('※{}成功複製到word'.format(file))
else:
shutil.copy2(input, './02_yolo_classify3/02_words/{}'.format(file_name))
print('※{}成功複製到words'.format(file))
print(' 沒有字:{}張'.format(l))
print(' 1個字:{}張'.format(m))
print(' 2個字以上:{}張'.format(n))
儲存/讀取圖檔
# 儲存已完成前處理之圖檔(中文路徑)
def saveClassify(image, output, p):
cv2.imencode(ext='.jpg', img=image)[1].tofile(output)
print('第{}張框字並儲存成功'.format(p))
# 讀取圖檔(中文路徑)
cv2.imdecode(np.fromfile(img_path, dtype=np.uint8), -1)
圖檔裁切
3.1 裁切:物件偵測框線設定為2px,裁切時須要注意是否會超出圖片範圍。
#框選偵測到的物件,並裁切
def drawBox(image, classes, confs, boxes):
new_image = image.copy()
cut_img_list = []
for (classid, conf, box) in zip(classes, confs,boxes):
x, y, w, h = box
# 避免x, y軸超出圖片範圍
if x - 2 < 0:
x = 2
if y - 2 < 0:
y = 2
# 畫出物件偵測框
cv2.rectangle(new_image, (x - 2, y - 2), (x + w + 2, y + h + 2), (0, 255, 0), 2)
# 裁切偵測框內的中文字
cut_img = img[y:y + h + 2, x:x + w + 2]
cut_img_list.append(cut_img)
return new_image, cut_img_list[0]
3.2 裁切後圖檔,存檔時覆蓋新資料集(分類後的圖檔)。
if __name__ == '__main__':
# 主辦單位提供的資料集(約7萬張)
source = './01_origin/'
files = os.listdir(source)
# 依照正整數排序
files.sort(key=lambda x:int(x[:-6]))
model = initNet()
for file in files:
img = cv2.imdecode(np.fromfile(source+file,dtype=np.uint8), -1)
classes, confs, boxes = nnProcess(img, model)
try:
frame, cut = drawBox(img, classes, confs, boxes)
# 框選後的照片
frame = cv2.resize(frame, (240, 200), interpolation=cv2.INTER_CUBIC)
# 顯示框選後的圖片
cv2.imshow('img', frame)
# 裁切後的照片
cut2 = cv2.resize(cut, (80, 60), interpolation=cv2.INTER_CUBIC)
cv2.imshow('cut', cut2)
cv2.waitKey()
saveClassify(cut2, './02_yolo_classify3/cut2/' + file, p) #儲存裁切後的照片
except:
continue
print('程式執行完畢')
3.3 成果
裁切前
裁切後
標籤錯誤:
「達成人工智慧之前,免不了先經歷工人智慧」。夥伴們人數眾多,逐張檢查圖檔標籤,並手動更正標籤。
整整有6.6萬張圖檔,夥伴們除了耗費大量時間檢查修正,甚至可能頭昏眼花看錯,效率低下。(痛苦程度300分)
若大家有更好的標籤勘誤技巧,請留言告訴我,謝謝!
標籤不在800字內
5.1 800字字典(txt檔)
5.2 判定標籤是否在800字內,程式碼如下。
import os
import shutil
#讀取txt檔
def read_dicts(path):
file1 = open(path, 'rt', encoding="utf-8")
words = file1.read().split('\n')
file1.close()
return words
#判定是否屬於字典中的字
def chech_in_dicts(source, words):
files = os.listdir(source)
files.sort(key=lambda x:int(x[:-6]))
move_record = ''
print('※開始判定是否屬於字典中的字...')
for file in files:
if file[-5:-4] in words:
print('{}在字典裡'.format(file))
else:
print('{}不在字典裡'.format(file))
file += ','
move_record += file
print('判定完畢')
return move_record
#移動檔案到目標資料夾
def move_to_des(move_record, source, destination):
move_list = move_record.split(',')[:-1]
print('※開始移動檔案到目標資料夾')
for move_it in move_list:
shutil.move(source+move_it, destination)
print('{}已成功移動到資料夾:其他字'.format(move_it))
print('移動完畢')
if __name__ == '__main__':
# training data dic.txt
dics = './data/training data dic.txt'
# 待判定的資料夾
source = './data/04_清洗標籤後圖片/origin/'
# 目的地資料夾
destination = './data/04_清洗標籤後圖片/800字外/'
words = read_dicts(dics)
move_record = chech_in_dicts(source, words)
move_to_des(move_record, source, destination)
5.3 成果
成功篩除標籤名稱不在800字內的圖檔
資料前處理後,目前剩下約6.2萬張可用圖檔,如下圖。
從3.3可以發現,清洗後的圖檔,部分仍有紅框或其他雜訊如下圖。
「若將圖檔轉換為灰階,會更容易進行影像處理(如:mask、Gaussian Blur)。此外,可提高模型訓練效率」。
因此,下一章的目標是:「分享如何以HSV去除紅框等雜訊,並將圖檔轉換為灰階圖」。
讓我們繼續看下去...